package org.zffc.common.util.hash;

import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;

import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.Security;

/**
 * SM3国密哈希算法工具类
 * (需要BouncyCastle库支持)
 */
public class Sm3Util {

    static {
        // 注册BouncyCastleProvider
        // 必须显式注册后，Java 的 Security API 才能找到SM3的实现
        // 如果没有注册，调用 MessageDigest.getInstance("SM3") 或使用 SM3Digest 时会抛出异常
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * 计算SM3哈希值
     *
     * @param input 原始数据
     * @return 64位小写SM3哈希字符串
     */
    private static String hash(byte[] input) {
        SM3Digest digest = new SM3Digest();
        digest.update(input, 0, input.length);
        byte[] hash = new byte[digest.getDigestSize()];
        digest.doFinal(hash, 0);
        return Hex.toHexString(hash);
    }

    /**
     * 计算字符串的SM3哈希值(默认UTF-8编码)
     *
     * @param input 原始字符串
     * @return 64位小写SM3哈希字符串
     */
    public static String hash(String input) {
        return hash(input.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 计算字符串的SM3哈希值(指定编码)
     *
     * @param input       原始字符串
     * @param charsetName 字符编码
     * @return 64位小写SM3哈希字符串
     */
    public static String sm3Encode(String input, String charsetName)
            throws UnsupportedEncodingException {
        return hash(input.getBytes(charsetName));
    }

    /**
     * 验证数据与SM3哈希是否匹配
     *
     * @param input   原始数据
     * @param sm3Hash 待验证的SM3哈希
     * @return 验证结果
     */
    private static boolean verify(byte[] input, String sm3Hash) {
        String calculatedHash = hash(input);
        return calculatedHash.equalsIgnoreCase(sm3Hash);
    }

    /**
     * 验证字符串与SM3哈希是否匹配(默认UTF-8编码)
     *
     * @param input   原始字符串
     * @param sm3Hash 待验证的SM3哈希
     * @return 验证结果
     */
    public static boolean verify(String input, String sm3Hash) {
        return verify(input.getBytes(StandardCharsets.UTF_8), sm3Hash);
    }

    /**
     * 带盐值的SM3哈希计算
     *
     * @param input 原始数据
     * @param salt  盐值
     * @return 加盐后的SM3哈希
     */
    private static String hashWithSalt(byte[] input, byte[] salt) {
        byte[] saltedInput = new byte[input.length + salt.length];
        System.arraycopy(input, 0, saltedInput, 0, input.length);
        System.arraycopy(salt, 0, saltedInput, input.length, salt.length);
        return hash(saltedInput);
    }
}